﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Xml.Serialization;
using System.IO;
using A2DFramework.Components;

namespace A2DFramework.EventService.DistributeEventBus
{
    public delegate void EventReceived(string evtClass, object evt);

    public class EventBusClientBroker
    {
        private A2DTcpClient client;
        public string ServerIdentity { get; set; }
        public event EventReceived NewEventReceived;
        public List<string> DependencyDlls{get;set;}

        public EventBusClientBroker(string remoteServer, int remotePort, string serverIdentity, string dependencyDlls)
        {
            client = new A2DTcpClient(remoteServer, remotePort);
            this.ServerIdentity = serverIdentity;
            DependencyDlls = new List<string>();
            string[] dlls = dependencyDlls.Split(',');
            foreach(string dll in dlls)
                if(dll.Trim().Length>0)
                    DependencyDlls.Add(dll.Trim());
            client.NewMessageReceived += new A2DTcpClientMessageReceived(client_NewMessageReceived);
        }

        private void client_NewMessageReceived(string msg)
        {
            string evtClassPath;
            string evtXml;
            if (Helper.IsEventBusCommand_Publish(msg, out evtClassPath, out evtXml))
            {
                object evt = null;
                foreach (string dll in DependencyDlls)
                {
                    Assembly ass = Assembly.LoadFrom(dll);
                    try
                    {
                        Type t = ass.GetType(evtClassPath);
                        if (t == null)
                            continue;

                        using (StringReader rdr = new StringReader(evtXml))
                        {
                            XmlSerializer serializer = new XmlSerializer(t);
                            evt = serializer.Deserialize(rdr);
                        }
                    }
                    catch
                    {
                        continue;
                    }
                }
                if (evt == null)
                    throw new Exception("Cannot deserialize xml to object exception.");

                if (this.NewEventReceived != null)
                    this.NewEventReceived.Invoke(evtClassPath, evt);
            }
        }

        public void Connect()
        {
            client.Connect();
            client.Send(Helper.GenerateDeclareCommand(ServerIdentity));
        }

        public bool IsConnected()
        {
            if (client == null)
                return false;
            return client.IsConnecting();
        }

        public void Subscribe<T>()
            where T : IEventBase
        {
            client.Send(Helper.GenerateSubscribeCommand<T>());
        }
        public void Subscribe(Type type)
        {
            client.Send(Helper.GenerateSubscribeCommand(type));
        }

        public void Publish<T>(T evt)
            where T : IEventBase
        {
            client.Send(Helper.GeneratePublishCommand<T>(evt));
        }
        public void Publish(IEventBase evt)
        {
            client.Send(Helper.GeneratePublishCommand(evt));
        }

        public void Close()
        {
            client.Close();
        }
    }
}
